﻿using System;
using Excel = Microsoft.Office.Interop.Excel;

namespace ExcelToWord.Common {
    internal class ExcelSource :IDisposable {

        #region Fields

        private Excel.Application app = new Excel.Application();
        private object missing = System.Reflection.Missing.Value;
        private Excel.Workbooks workBooks;
        private Excel.Workbook workBook;
        private Excel.Worksheet currentSheet;

        private string filename;
        private int titleRow = 1;
        private int dataStartRow = 2;
        private string sheetName = string.Empty;

        #endregion

        #region Properties

        internal int TitleRow {
            get { return titleRow; }
            set {
                if (value <= 0) {
                    throw new IndexOutOfRangeException("title row");
                }
                titleRow = value;
                dataStartRow = titleRow + 1;
            }
        }

        internal int DataStartRow {
            get { return dataStartRow; }
            set {
                if (value <= titleRow) {
                    throw new IndexOutOfRangeException("data start row");
                }
                dataStartRow = value;
            }
        }

        internal Excel.Sheets Sheets {
            get {
                if (workBook == null) {
                    throw new NullReferenceException("current sheet");
                }
                return workBook.Sheets;
            }
        }

        internal string SheetName {
            get { return sheetName; }
            set { 
                sheetName = value;
                if (workBook != null) {
                    currentSheet = (Excel.Worksheet)workBook.Sheets.get_Item(sheetName);
                }
            }
        }

        internal ExcelTitle[] Titles {
            get {
                if (currentSheet == null) {
                    throw new NullReferenceException("current sheet");
                }
                System.Collections.ArrayList titles = new System.Collections.ArrayList();
                for (int i = 1; i < currentSheet.Columns.Count; i++) {
                    Excel.Range range = (Excel.Range)currentSheet.Cells[titleRow, i];
                    if (!string.IsNullOrEmpty(range.Text.ToString())) {
                        titles.Add(new ExcelTitle(range.Text.ToString(), i));
                    }
                }
                return (ExcelTitle[])titles.ToArray(typeof(ExcelTitle));
            }
        }

        internal Excel.Range Cells {
            get {
                if (currentSheet == null) {
                    throw new NullReferenceException("current sheet");
                }
                return currentSheet.Cells;
            }
        }

        #endregion

        internal ExcelSource() {
            workBooks = app.Workbooks;
        }

        internal static ExcelSource Create() {
            return new ExcelSource();
        }

        internal void Open(string filename) {
            this.filename = filename;
            
            workBook = workBooks.Open(filename, missing,
                        true, missing,
                        missing, missing,
                        true, missing,
                        missing, missing,
                        missing, missing,
                        missing, missing,
                        missing);

            currentSheet = (Excel.Worksheet)workBook.ActiveSheet;
            sheetName = currentSheet.Name;
        }

        internal bool IsRowEmpty(int rowIdx) {
            return IsRowEmpty(rowIdx, -1);
        }

        internal bool IsRowEmpty(int rowIdx, int endColIdx) {

            if (currentSheet == null) {
                throw new NullReferenceException("current sheet");
            }

            int colCount = endColIdx;

            if (colCount <= 0) colCount = currentSheet.Cells.Columns.Count;

            for (int i = 1; i <= colCount; i++) {
                Excel.Range range = (Excel.Range)currentSheet.Cells[rowIdx, i];
                if (!string.IsNullOrEmpty(range.Text.ToString())) {
                    return false;
                }
            }

            return true;
        }

        #region IDisposable 成员

        public void Dispose() {
            try {
                currentSheet = null;
                workBook.Close(false, missing, missing);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(workBook);
            } catch {
                
            } 
            
            try {
                workBooks.Close();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(workBooks);
            } catch {
                
            } 

            try {
                app.Quit();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
            } catch {

            } finally {
                app = null;
                workBooks = null;
                workBook = null;
            }
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        #endregion
    }

    internal class ExcelTitle {

        private string name = string.Empty;
        private int columnIdx = 0;

        internal ExcelTitle(string name, int columnIdx) {
            this.name = name;
            this.columnIdx = columnIdx;
        }

        internal string Name {
            get { return name; }
        }

        internal int ColumnIdx {
            get { return columnIdx; }
        }

    }

}
